package com.xdcplus.web.service.tool.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageInfo;
import com.xdcplus.core.utils.BeanUtils;
import com.xdcplus.exceptions.XdcWebException;
import com.xdcplus.mom.constants.NumberConstant;
import com.xdcplus.mom.enums.RegionTypeEnum;
import com.xdcplus.mom.enums.ResponseEnum;
import com.xdcplus.mp.service.impl.BaseServiceImpl;
import com.xdcplus.mp.utils.PageableUtils;
import com.xdcplus.mp.utils.PropertyUtils;
import com.xdcplus.pager.vo.PageVO;
import com.xdcplus.system.api.DepartmentRemote;
import com.xdcplus.web.common.enums.ToolInfoIsMainControlEnum;
import com.xdcplus.web.common.pojo.dto.GetToolByWoCodeAndOpeAndUnitTypeDto;
import com.xdcplus.web.common.pojo.dto.bd.BdOpeFilterDTO;
import com.xdcplus.web.common.pojo.dto.tool.ToolInfoDTO;
import com.xdcplus.web.common.pojo.dto.tool.ToolInfoFilterDTO;
import com.xdcplus.web.common.pojo.entity.bd.BdFactory;
import com.xdcplus.web.common.pojo.entity.tool.ToolInfo;
import com.xdcplus.web.common.pojo.query.GetToolByWoCodeAndOpeAndUnitTypeQuery;
import com.xdcplus.web.common.pojo.query.tool.ToolInfoQuery;
import com.xdcplus.web.common.pojo.vo.alarm.ToolSimpleVo;
import com.xdcplus.web.common.pojo.vo.bd.BdOpeVO;
import com.xdcplus.web.common.pojo.vo.tool.ToolInfoVO;
import com.xdcplus.web.mapper.bd.BdFactoryMapper;
import com.xdcplus.web.mapper.tool.ToolInfoMapper;
import com.xdcplus.web.service.bd.BdFactoryService;
import com.xdcplus.web.service.bd.BdOpeService;
import com.xdcplus.web.service.tool.ToolGroupService;
import com.xdcplus.web.service.tool.ToolInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备信息(ToolInfo)表服务实现类
 *
 * @author Fish.Fei
 * @since 2023-02-03 15:52:13
 */
@Slf4j
@Service("toolInfoService")
public class ToolInfoServiceImpl extends BaseServiceImpl<ToolInfoMapper, ToolInfo, ToolInfo, ToolInfoVO> implements ToolInfoService {

    @Autowired
    protected ToolInfoMapper toolInfoMapper;

    @Autowired
    protected DepartmentRemote departmentRemote;

    @Autowired
    protected BdOpeService bdOpeService;

    @Autowired
    protected BdFactoryMapper bdFactoryMapper;

    @Autowired
    protected BdFactoryService bdFactoryService;
    @Autowired
    protected ToolGroupService toolGroupService;
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean saveToolInfo(ToolInfoDTO toolInfoDTO) {
        Long codeCount = toolInfoMapper.selectCount(new QueryWrapper<ToolInfo>()
                .eq("TOOL_CODE", toolInfoDTO.getToolCode())
                .or()
                .eq("TOOL_NAME", toolInfoDTO.getToolName())
        );
        Assert.isTrue(Validator.equal(codeCount,NumberConstant.ZERO.longValue()),ResponseEnum.CODE_NAME_ALREADY_EXISTS.getMessage());


        ToolInfo toolInfo = new ToolInfo();
        BeanUtil.copyProperties(toolInfoDTO, toolInfo);
        toolInfo.setCreatedTime(new Timestamp(DateUtil.current()));

        return this.save(toolInfo);
    }

    @Override
    public List<ToolInfoVO> queryByParentId(Long toolIdFk) {
        return objectConversion(baseMapper.queryToolInfoByParentIds(Arrays.asList(toolIdFk)));
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean updateToolInfo(ToolInfoDTO toolInfoDTO) {

        ToolInfo toolInfo = this.getById(toolInfoDTO.getId());
        if (ObjectUtil.isNull(toolInfo)) {
            log.error("updateToolInfo() The ToolInfo does not exist or has been deleted");
            throw new XdcWebException(ResponseEnum.ERROR);
        }

        /// 验证名称是否重复
        LambdaQueryWrapper<ToolInfo> toolInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        toolInfoLambdaQueryWrapper.eq(ToolInfo::getToolName,toolInfoDTO.getToolName());
        toolInfoLambdaQueryWrapper.ne(ToolInfo::getId,toolInfo.getId());
        if (baseMapper.selectCount(toolInfoLambdaQueryWrapper) > NumberConstant.ZERO) {
            throw new XdcWebException(ResponseEnum.NAME_ALREADY_EXISTS);
        }

        /// 主设备的产线变更后，子设备需要同步
        if (toolInfo.getIsMainControl().equals(ToolInfoIsMainControlEnum.MAIN.getMsg())) {
            if (!toolInfoDTO.getBayId().equals(toolInfo.getBayId())) {
                LambdaUpdateWrapper<ToolInfo> toolInfoLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                toolInfoLambdaUpdateWrapper.eq(ToolInfo::getParentIdFk,toolInfo.getId());
                toolInfoLambdaUpdateWrapper.set(ToolInfo::getBayId,toolInfoDTO.getBayId());
                this.update(toolInfoLambdaUpdateWrapper);
            }
        }

        /// 排除编号不能修改
        /// 子设备不能修改产线。
        if (toolInfo.getIsMainControl().equals(ToolInfoIsMainControlEnum.SUB.getCode())) {
            BeanUtil.copyProperties(toolInfoDTO, toolInfo, new String[]{"toolCode","bayId"});
        }else {
            BeanUtil.copyProperties(toolInfoDTO, toolInfo, "toolCode");
        }
        toolInfo.setUpdatedUser(toolInfoDTO.getUpdatedUser());
        toolInfo.setUpdatedTime(new Timestamp(DateUtil.current()));

        return this.updateById(toolInfo);

    }

    @Override
    public Boolean saveOrUpdateBatch(List<ToolInfo> toolInfoList) {

        toolInfoList.forEach(toolInfo -> {
            ToolInfo toolInfoParam = new ToolInfo();
            toolInfoParam.setId(toolInfo.getId());
            if (ObjectUtil.isNotNull(toolInfo.getId())) {
                toolInfo.setId(toolInfo.getId());
                toolInfo.setUpdatedTime(new Timestamp(DateUtil.current()));
                LambdaUpdateWrapper<ToolInfo> lambdaUpdate = Wrappers.lambdaUpdate();
                lambdaUpdate.eq(ToolInfo::getId, toolInfo.getId());
                update(toolInfo, lambdaUpdate);
            } else {
                toolInfo.setCreatedTime(new Timestamp(DateUtil.current()));
                save(toolInfo);
            }
        });
        return true;
    }

    @Override
    public Boolean saveOrUpdateBatchByDTOList(List<ToolInfoDTO> toolInfoDTOList) {

        List<ToolInfo> toolInfoList = BeanUtils.copyProperties(toolInfoDTOList, ToolInfo.class);
        return saveOrUpdateBatch(toolInfoList);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean deleteToolInfoLogical(Long id) {

        Assert.notNull(id, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());

        ToolInfo toolInfo = this.getById(id);

        if (ObjectUtil.isNull(toolInfo)) {
            log.error("deleteToolInfo() The ToolInfo does not exist or has been deleted");
            throw new XdcWebException(ResponseEnum.ERROR);
        }

        /// 验证判断是否存在子设备，提示
        if (toolInfo.getIsMainControl().equals(ToolInfoIsMainControlEnum.MAIN.getMsg())) {
            LambdaQueryWrapper<ToolInfo> toolInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
            toolInfoLambdaQueryWrapper.eq(ToolInfo::getParentIdFk,toolInfo.getId());
            Assert.isTrue(baseMapper.selectCount(toolInfoLambdaQueryWrapper).intValue() == NumberConstant.ZERO,
                    ResponseEnum.SUB_TOOL_EXISTS_ERROR.getMessage());
        }

        return this.removeById(id);


    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean deleteToolInfoByIds(String ids) {
        Assert.notNull(ids, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());
        List<String> idList = Arrays.asList(ids.split(","));
        if (CollectionUtil.isEmpty(idList)) {
            throw new XdcWebException(ResponseEnum.ERROR);
        }
        idList.forEach(id -> {
            ToolInfo toolInfo = this.getById(id);
            if (ObjectUtil.isNull(toolInfo)) {
                log.error("deleteToolInfo() The ToolInfo does not exist or has been deleted");
                throw new XdcWebException(ResponseEnum.ERROR);
            }
        });

        return this.removeByIds(idList);
    }

    private List<ToolInfo> queryToolInfoList(ToolInfoFilterDTO toolInfoFilterDTO) {
        ToolInfoQuery toolInfoQuery = BeanUtil.copyProperties(toolInfoFilterDTO, ToolInfoQuery.class);

        ///通过工艺信息查询设备群组
        if (ObjectUtil.isNotEmpty(toolInfoFilterDTO.getOpeCode())) {
            BdOpeFilterDTO bdOpeFilterDTO = new BdOpeFilterDTO();
            bdOpeFilterDTO.setOpeCode(toolInfoFilterDTO.getOpeCode());
            List<BdOpeVO> bdOpeVOS = bdOpeService.queryBdOpeVOList(bdOpeFilterDTO);
            if (!bdOpeVOS.isEmpty()) {
                toolInfoQuery.setToolGroupIds(
                        bdOpeVOS.stream().map(BdOpeVO::getToolGroupIdFk).distinct().collect(Collectors.toList())
                );
            }
        }

        return toolInfoMapper.queryToolInfo(toolInfoQuery);
    }

    @Override
    public List<ToolInfoVO> queryToolInfoVOList(ToolInfoFilterDTO toolInfoFilterDTO) {
        return this.objectConversion(queryToolInfoList(toolInfoFilterDTO));
    }

    @Override
    public PageVO<ToolInfoVO> queryToolInfo(ToolInfoFilterDTO toolInfoFilterDTO) {
        PageVO<ToolInfoVO> pageVO = new PageVO<>();

        if (toolInfoFilterDTO.getCurrentPage() > NumberConstant.ZERO) {
            PageableUtils.basicPage(toolInfoFilterDTO.getCurrentPage(), toolInfoFilterDTO.getPageSize(),
                    toolInfoFilterDTO.getOrderType(), toolInfoFilterDTO.getOrderField());
        }

        List<ToolInfo> toolInfoList = queryToolInfoList(toolInfoFilterDTO);
        /// 装配产线信息
        List<String> regionCodes = toolInfoList.stream().map(ToolInfo::getBayId).collect(Collectors.toList());

        /// 查询产线名称
        Map<String, String> regionCode2NameMap;
        if (!regionCodes.isEmpty()) {
            LambdaQueryWrapper<BdFactory> bdFactoryLambdaQueryWrapper = new LambdaQueryWrapper<>();
            bdFactoryLambdaQueryWrapper.eq(BdFactory::getRegionType, RegionTypeEnum.LINE.getCode());
            bdFactoryLambdaQueryWrapper.in(BdFactory::getRegionCode,regionCodes);
            regionCode2NameMap = bdFactoryMapper.selectList(bdFactoryLambdaQueryWrapper).stream().collect(Collectors.toMap(BdFactory::getRegionCode,
                    BdFactory::getRegionName));
        } else {
            regionCode2NameMap = new HashMap<>();
        }

        List<ToolInfoVO> records = this.objectConversion(toolInfoList);

        PageInfo<ToolInfo> pageInfo = new PageInfo<>(toolInfoList);
        PropertyUtils.copyProperties(pageInfo, pageVO, records);

        return pageVO;
    }

    @Override
    public ToolInfoVO queryToolInfoById(Long id) {

        Assert.notNull(id, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());

        return this.objectConversion(this.getById(id));
    }

    @Override
    public ToolInfoVO getToolInfoVoByToolCode(String toolCode) {
        return this.objectConversion(toolInfoMapper.queryToolInfoByToolCode(toolCode));
    }
    @Override
    public ToolInfo queryToolInfoByToolCode(String toolCode){
        return toolInfoMapper.queryToolInfoByToolCode(toolCode);
    }

    @Override
    public List<ToolInfoVO> getToolInfoByClassify(Long toolClassifyId) {
        return toolInfoMapper.getToolInfoByClassify(toolClassifyId);
    }

    @Override
    public List<ToolSimpleVo> queryCurrentAndChildByFactoryId(Long factoryId) {
        return toolInfoMapper.queryCurrentAndChildByFactoryId(factoryId);

    }

    @Override
    public String getToolNameById(Long id) {
        if (id == null) {
            return null;
        }
        ToolInfo toolInfo = this.getById(id);
        if (toolInfo != null) {
            return toolInfo.getToolName();
        }
        return null;
    }

    @Override
    public String getToolNameByToolCode(String toolCode) {
        if ("PE".equals(toolCode)) {
            return "包装流水线";
        }
        ToolInfo toolInfo=toolInfoMapper.queryToolInfoByToolCode(toolCode);
        if(toolInfo!=null){
            return toolInfo.getToolName();
        }
        return null;
    }

    @Override
    public List<ToolInfoVO> getByRootToolId(Long rootToolId) {
        return this.objectConversion(toolInfoMapper.getByRootToolId(rootToolId));
    }

    @Override
    public List<Long> getToolIdFkByRootToolId(Long rootToolId) {
        if (rootToolId == null) {
            return null;
        }
        List<ToolInfo> toolInfoList = toolInfoMapper.getByRootToolId(rootToolId);
        if (CollectionUtil.isNotEmpty(toolInfoList)) {
            return toolInfoList.stream().map(ToolInfo::getId).distinct().collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public ToolInfoVO objectConversion(ToolInfo s) {
        ToolInfoVO toolInfoVO = super.objectConversion(s);
        if(toolInfoVO.getParentIdFk()!=null && !Validator.equal(toolInfoVO.getParentIdFk(),NumberConstant.ZERO.longValue())){
            ToolInfo toolInfoParent = toolInfoMapper.selectById(toolInfoVO.getParentIdFk());
            toolInfoVO.setParentCode(toolInfoParent.getToolCode());
        }

//        Optional.ofNullable(toolInfoVO.getDeptIdFk()).ifPresent(a->toolInfoVO.setDepartmentVO(ResponseUtils.getResponse(departmentRemote.queryDepartmentById(a))));
//        Optional.ofNullable(toolInfoVO.getToolClassifyIdFk()).ifPresent(a->toolInfoVO.setToolClassifyVO(toolClassifyService.queryToolClassifyById(a)));
//        Optional.ofNullable(toolInfoVO.getToolTypeIdFk()).ifPresent(a->toolInfoVO.setToolTypeVO(toolTypeService.queryToolTypeById(a)));
//        Optional.ofNullable(toolInfoVO.getToolModelIdFk()).ifPresent(a->toolInfoVO.setToolModelVO(toolModelService.queryToolModelById(a)));
//        Optional.ofNullable(toolInfoVO.getFactoryIdFk()).ifPresent(a->toolInfoVO.setBdFactoryVO(bdFactoryService.queryBdFactoryById(a)));
//        Optional.ofNullable(toolInfoVO.getOpeIdFk()).ifPresent(a->toolInfoVO.setBdOpeVO(bdOpeService.queryBdOpeById(a)));

        return toolInfoVO;
    }

    @Override
    public List<ToolInfoVO> objectConversion(List<ToolInfo> sList) {
        if (!CollectionUtil.isNotEmpty(sList)) {
            return null;
        } else {
            List<ToolInfoVO> tList = new ArrayList();
            Iterator var3 = sList.iterator();

            while(var3.hasNext()) {
                ToolInfo s = (ToolInfo)var3.next();
                ToolInfoVO t = this.objectConversion(s);
                Optional.ofNullable(t).ifPresent(tList::add);
            }

            return tList;
        }
    }


    @Override
    public List<ToolInfoVO> getToolByWoCodeAndOpeAndUnitType(GetToolByWoCodeAndOpeAndUnitTypeDto getToolByWoCodeAndOpeAndUnitTypeDto) {
        GetToolByWoCodeAndOpeAndUnitTypeQuery getToolByWoCodeAndOpeAndUnitTypeQuery=new GetToolByWoCodeAndOpeAndUnitTypeQuery();
        BeanUtil.copyProperties(getToolByWoCodeAndOpeAndUnitTypeDto, getToolByWoCodeAndOpeAndUnitTypeQuery);
        return this.objectConversion(toolInfoMapper.getToolByWoCodeAndOpeAndUnitType(getToolByWoCodeAndOpeAndUnitTypeQuery));
    }


    @Override
    public List<String> findSubToolByQa(Long toolId, Long opeId) {
        if(opeId==null || toolId==null){
            throw new XdcWebException(ResponseEnum.QA_TOOL_SELECT_FAILD);
        }
//        BdOpeVO bdOpeVO = bdOpeService.queryBdOpeById(opeId);
//        if(!StrUtil.equalsAny(bdOpeVO.getOpeCode(),"ALD_Z","PECVD","PRT")){
//            throw new XdcWebException(ResponseEnum.QA_TOOL_SELECT_FAILD);
//        }

        ToolInfoQuery toolInfoQuery =new ToolInfoQuery();
        toolInfoQuery.setParentIdFk(toolId);
        toolInfoQuery.setIsMainControl(ToolInfoIsMainControlEnum.SUB.getMsg());
        List<ToolInfo> toolInfos = toolInfoMapper.queryToolInfo(toolInfoQuery);
        if(CollectionUtil.isEmpty(toolInfos)){
            return null;
        }

        return toolInfos.stream().map(ToolInfo::getToolCode).collect(Collectors.toList());
    }

    @Override
    public PageVO<ToolInfoVO> pageToolInfoForTree(ToolInfoFilterDTO toolInfoFilterDTO) {
        PageVO<ToolInfoVO> pageVO = new PageVO<>();

        if (toolInfoFilterDTO.getCurrentPage() > NumberConstant.ZERO) {
            PageableUtils.basicPage(
                    toolInfoFilterDTO.getCurrentPage(),toolInfoFilterDTO.getPageSize(),
                    toolInfoFilterDTO.getOrderType(),toolInfoFilterDTO.getOrderField());
        }

        ToolInfoQuery toolInfoQuery = new ToolInfoQuery();
        BeanUtil.copyProperties(toolInfoFilterDTO,toolInfoQuery);

        ///通过工艺信息查询设备群组
        if (ObjectUtil.isNotEmpty(toolInfoFilterDTO.getOpeCode())) {
            BdOpeFilterDTO bdOpeFilterDTO = new BdOpeFilterDTO();
            bdOpeFilterDTO.setOpeCode(toolInfoFilterDTO.getOpeCode());
            List<BdOpeVO> bdOpeVOS = bdOpeService.queryBdOpeVOList(bdOpeFilterDTO);
            if (!bdOpeVOS.isEmpty()) {
                toolInfoQuery.setToolGroupIds(
                        bdOpeVOS.stream().map(BdOpeVO::getToolGroupIdFk).distinct().collect(Collectors.toList())
                );
            }
        }

        if (ObjectUtil.isNotEmpty(toolInfoQuery.getToolName())) {
            toolInfoQuery.setToolName(toolInfoQuery.getToolName().replaceAll("_","\\\\_"));
        }
        if (ObjectUtil.isNotEmpty(toolInfoQuery.getToolCode())) {
            toolInfoQuery.setToolCode(toolInfoQuery.getToolCode().replaceAll("_","\\\\_"));
        }

        List<ToolInfo> toolInfos = toolInfoMapper.pageToolInfoForTree(toolInfoQuery);

        /// 装配产线信息
        List<String> regionCodes = toolInfos.stream().map(ToolInfo::getBayId).distinct().collect(Collectors.toList());

        /// 查询产线名称
        Map<String, String> regionCode2NameMap;
        if (!regionCodes.isEmpty()) {
            LambdaQueryWrapper<BdFactory> bdFactoryLambdaQueryWrapper = new LambdaQueryWrapper<>();
            bdFactoryLambdaQueryWrapper.in(BdFactory::getRegionCode,regionCodes);
            regionCode2NameMap = bdFactoryMapper.selectList(bdFactoryLambdaQueryWrapper).stream().collect(Collectors.toMap(BdFactory::getRegionCode,
                    BdFactory::getRegionName));
        } else {
            regionCode2NameMap = new HashMap<>();
        }

        PageInfo<ToolInfo> pageInfo = new PageInfo<>(toolInfos);
        PropertyUtils.copyProperties(pageInfo, pageVO, this.objectConversion(toolInfos));
        /// 拼接子设备
        List<Long> parentIds = toolInfos.stream().map(ToolInfo::getId).distinct().collect(Collectors.toList());
        Map<Long, List<ToolInfo>> toolInfoMap;
        if (!parentIds.isEmpty()) {
            List<ToolInfo> toolInfos1 = toolInfoMapper.queryToolInfoByParentIds(parentIds);
            if (!toolInfos1.isEmpty()) {
                toolInfoMap = toolInfos1.stream().collect(Collectors.groupingBy(ToolInfo::getParentIdFk));
            }else {
                toolInfoMap = new HashMap<>();
            }
        }else {
            toolInfoMap = new HashMap<>();
        }

        if (pageVO.getRecords() != null) {
            pageVO.getRecords().forEach(toolInfoVO -> {

                if (toolInfoMap.containsKey(toolInfoVO.getId())) {
                    if (ObjectUtil.isNotNull(toolInfoMap.get(toolInfoVO.getId()))) {

                        List<ToolInfoVO> children = this.objectConversion(toolInfoMap.get(toolInfoVO.getId()));
                        toolInfoVO.setChildren(children);
                    }
                }
            });
        }

        return pageVO;

    }

    @Override
    public List<ToolInfoVO> getToolByOpeCode(String opeCode) {
        return this.objectConversion(toolInfoMapper.getToolByOpeCode(opeCode));
    }


    @Override
    public List<ToolInfoVO> getToolByFactoryId(String factoryId) {
        return this.objectConversion(toolInfoMapper.getToolByFactoryId(factoryId));
    }

    @Override
    public List<ToolInfoVO> getToolByOpeAndTypeCode(String opeCode, String toolTypeCode) {
        return this.objectConversion(toolInfoMapper.getToolByOpeAndTypeCode(opeCode,toolTypeCode));
    }

}
